package com.example.demo.utils;

import com.example.demo.exception.PasswordErrorException;
import java.net.SocketTimeoutException;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.TesseractException;
import org.jsoup.Connection;
import org.jsoup.Connection.Method;
import org.jsoup.Connection.Response;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


/**
 * 登陆湖工大教务系统工具类
 *
 * @author lizijian
 */
@Slf4j
public class HbutLoginUtil {
    private static final String TITLE = "湖北工业大学 -- 统一身份认证";
    private static final String LOGIN_SSO_URL = "https://sso.hbut.edu.cn:7002/cas/login?service=http://run.hbut.edu.cn/Account/sso";
    private static final String ALL_CLASS_URL = "http://run.hbut.edu.cn/ArrangeTask/Index";
    private static final String OWN_INFO_URL = "http://run.hbut.edu.cn/T_Student/OwnInfo";
    private static final String RIGHT_PLACE_SCHEDULE_URL = "http://run.hbut.edu.cn/ArrangeTask/RightPlaceSchedule?ClassRoom=";
    private static final String PLACE_SCHEDULE_URL = "http://run.hbut.edu.cn/ArrangeTask/PlaceSchedule";
    private static final String LOGIN_FOR_JSON_URL = "http://run.hbut.edu.cn/Account/LogOnForJson";
    private static final String CLASS_SCHEDULE_URL = "http://run.hbut.edu.cn/ArrangeTask/ClassSchedule?ClassName=";
    private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36";
    private static final Map<String,String> USER_MAP=new HashMap<>(8);
    private static  Set<Entry<String, String>> entrySet;
    private static final AtomicInteger CURRENT_USER =new AtomicInteger(0);
    private static final String MY_SCHEDULE_URL = "http://run.hbut.edu.cn/ArrangeTask/MyselfSchedule";
    private static final String STUDENT_GRADES_URL = "http://run.hbut.edu.cn/StuGrade/";


    static {
        USER_MAP.put("1910300711","2021HBUTeduCN");
        USER_MAP.put("1810411226","8874025");
        USER_MAP.put("1910300109","nWTJMdgRvHox");
        USER_MAP.put("1910300104", "990324863");
        entrySet= USER_MAP.entrySet();
    }
    /**
     * 使用cookie获取指定url的doc
     *
     * @param url 获取doc的url
     * @return doc
     * @throws IOException
     */
    private static Document getDocWithCookie(String url, Map<String, String> cookie) throws IOException {
        if (cookie != null) {
            Document document = Jsoup.connect(url).cookies(cookie).header("User-Agent", USER_AGENT).timeout(10000).get();
            //登录成功
            if (!"登录页面".equals(document.select("title").text())) {
                return document;
            }
        }
        return null;
    }

    /**
     * 设置请求参数
     */
    private static Map<String, String> getDataMapForCard(String username, String password,String verifyCode) {
        Map<String, String> dateMap = new HashMap<>(16);
        dateMap.put("__EVENTTARGET", "btnLogin");
        dateMap.put("__VIEWSTATE", "/wEPDwUKMTM4OTU1Nzc4NA8WAh4Hc3lzSW5mbzKSBQABAAAA/////wEAAAAAAAAADAIAAABPTmV3Y2FwZWMuVW5pdmVyc2FsU1MuRFRPLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAwDAAAAUk5ld2NhcGVjLlVuaXZlcnNhbFNTLkVudGl0eSwgVmVyc2lvbj0xLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAAChOZXdjYXBlYy5Vbml2ZXJzYWxTUy5EVE8uRFRPX09VVF9TWVNJTkZPBAAAAB48T1BFUkFUSU9OTU9ERT5rX19CYWNraW5nRmllbGQbRFRPX1dTUnVuUmVzdWx0K19yZXN1bHRDb2RlGkRUT19XU1J1blJlc3VsdCtfcmVzdWx0TXNnHURUT19XU1J1blJlc3VsdCtfRWNhcmRWZXJzaW9uBAEBBDNOZXdjYXBlYy5Vbml2ZXJzYWxTUy5FbnRpdHkuRW51bS5FbnVtX09QRVJBVElPTk1PREUDAAAAMk5ld2NhcGVjLlVuaXZlcnNhbFNTLkVudGl0eS5FbnVtLkVudW1fRWNhcmRWZXJzaW9uAwAAAAIAAAAF/P///zNOZXdjYXBlYy5Vbml2ZXJzYWxTUy5FbnRpdHkuRW51bS5FbnVtX09QRVJBVElPTk1PREUBAAAAB3ZhbHVlX18ACAMAAAABAAAABgUAAAABMQYGAAAADOaJp+ihjOaIkOWKnwX5////Mk5ld2NhcGVjLlVuaXZlcnNhbFNTLkVudGl0eS5FbnVtLkVudW1fRWNhcmRWZXJzaW9uAQAAAAd2YWx1ZV9fAAgDAAAAQAAAAAsWAgIDD2QWBgICDxYCHgdWaXNpYmxlaGQCAw8PFgIfAWhkFgJmDw8WAh4EVGV4dAUIMDAwMDAwMDBkZAILDw8WAh4LTmF2aWdhdGVVcmwFI2h0dHBzOi8vZWNhcmQubmV1LmVkdS5jbi9zZWxmc2VhcmNoZGRk4UyXgSmfuudOXEjQ0/+3KpTiyS8Jeyl0CdfFj3pPlDw=");
        dateMap.put("txtUserName", username);
        dateMap.put("txtPassword", password);
        dateMap.put("txtVaildateCode",verifyCode);
        dateMap.put("hfIsManager", "0");
        dateMap.put("__EVENTVALIDATION","/wEWBgLHu7XoDQKl1bKzCQK1qbSRCwLTtPqEDQLkysKABAKC3IeGDE2M2t8CPfcbMTYOKy1c3pc2bc2kCbpnHwbqWCEZ/6cE");
        return dateMap;
    }

    public static Map<String, String> loginCard() throws IOException, TesseractException {
        Map<String, String> cookies = Jsoup.connect(
                "http://ecard.hbut.edu.cn/SelfSearch/Login.aspx")
            .execute().cookies();
        String verifyCode = VerifyCodeUtil.getHbutCardVerifyCode(cookies);
        Map<String, String> data = getDataMapForCard("1910300711", "033814",verifyCode);
        Response response = Jsoup.connect("http://ecard.hbut.edu.cn/SelfSearch/Login.aspx")
            .data(data).cookies(cookies).execute();
        cookies.putAll(response.cookies());
        return cookies;
    }

    public static void getHbutCardDoc() throws TesseractException, IOException {
        Map<String, String> cookie = loginCard();
        System.out.println(cookie);
        Map<String,String> data=new HashMap<>(16);
        data.put("__VIEWSTATE","/wEPDwUINDEyMzA5NDkPFgIeCFNvcnRUeXBlBQNBU0MWAmYPZBYCAgMPZBYCAgMPZBYCAgQPPCsAEQIADxYEHgtfIURhdGFCb3VuZGceC18hSXRlbUNvdW50ZmQBEBYAFgAWABYCZg9kFgJmD2QWAgIBD2QWAgIBDw8WBB4IQ3NzQ2xhc3MFClNvcnRCdF9Bc2MeBF8hU0ICAmRkGAEFImN0bDAwJENvbnRlbnRQbGFjZUhvbGRlcjEkZ3JpZFZpZXcPPCsADAEIZmQDa9tdwwo0IzJIdko4FM340Bn+qvbzw2xku4IrpbQgSw==");
        data.put("__EVENTVALIDATION","/wEWCAKe1eeYDAL4s9G2CQLns9G2CQLo3PvYBQKQz7OvAgK0zsCfBwL3uvOGAgLk75bKAl6TJLnb3Fv9JSUH+NbgxiWGstGIr15eZbeLJ7tjSWAp");
        data.put("ctl00$ContentPlaceHolder1$rbtnType","0");
        data.put("ctl00$ContentPlaceHolder1$txtStartDate","2021-09-18");
        data.put("ctl00$ContentPlaceHolder1$txtEndDate","2021-09-25");
        data.put("ctl00$ContentPlaceHolder1$btnSearch","查  询");
        Document document = Jsoup.connect(
                "http://ecard.hbut.edu.cn/SelfSearch/User/ConsumeInfo.aspx").data(data).cookies(cookie)
            .post();
        Elements gridViewStyle = document.getElementsByClass("GridViewStyle");
        Elements tr = gridViewStyle.select("tr");
        for (int i=1;i< tr.size();i++) {
            Elements td = tr.get(i).select("td");
            System.out.println(td.text());
        }
    }

    public static Document getArbitrarilyCourseDoc(String username,String password)
        throws PasswordErrorException, IOException {
        Map<String, String> cookie = login(username, password);
        Response response = Jsoup.connect(
            "http://run.hbut.edu.cn/SelectCurriculum/AnyElectiveIndex").cookies(cookie).execute();
        return response.parse();
    }



    /**
     * 登陆湖工大教务系统,使用双地址,使用用户账号登陆
     */
    public static Map<String, String> login(String username, String password) throws PasswordErrorException, IOException {
        try {
            return loginSso(username, password);
        }catch (PasswordErrorException passwordErrorException){
            log.error(username+"-"+password+"-登录门户密码错误");
            return loginForJson(username, password);
        }catch (SocketTimeoutException socketTimeoutException){
            log.error(username+"-"+password+"-登录门户超时");
            return loginForJson(username, password);
        }
    }


    /**
     * 登陆湖工大教务系统,使用LogOnForJson地址,使用用户账号登陆
     */
    public static Map<String, String> loginForJson(String username, String password) throws PasswordErrorException, IOException {
        Map<String, String> dataMap = getDataMapLoginForJson(username, password);
        Connection connection = Jsoup.connect(LOGIN_FOR_JSON_URL);
        Connection.Response response=null;
        response = connection.ignoreContentType(true).header("User-Agent",USER_AGENT).method(Connection.Method.POST).data(dataMap).timeout(10000).execute();
        log.info(LogUtil.getMessage("body:" + response.body()));
        Map<String, String> cookies = response.cookies();
        //未登录成功,尝试登陆湖工大首页
        if (cookies.get("Role") == null) {
            throw new PasswordErrorException();
        }
        return response.cookies();
    }

    /**
     * 登陆湖工大教务系统,使用LogOnForJson地址,使用默认账号登陆
     *
     * @return 登陆后获取的cookie
     * @throws PasswordErrorException 密码错误
     */
    public static Map<String, String> login() throws PasswordErrorException, IOException {
        if(CURRENT_USER.get()>=entrySet.size()){
            CURRENT_USER.set(0);
        }
        int i=0;
        String username=null;
        String password=null;
        for (Entry<String, String> entry : entrySet) {
            if(i== CURRENT_USER.get()){
                username= entry.getKey();
                password= entry.getValue();
                break;
            }
            i++;
        }
        log.info(LogUtil.getMessage("username:"+username+" password:"+password));
        CURRENT_USER.incrementAndGet();
        Map<String, String> dataMap = getDataMapLoginForJson(username, password);
        Connection connection = Jsoup.connect(LOGIN_FOR_JSON_URL);
        connection.userAgent(USER_AGENT);
        Connection.Response response = connection.ignoreContentType(true).method(Method.GET).data(dataMap).timeout(10000).execute();
        log.info(LogUtil.getMessage("body:" + response.body()));
        Map<String, String> cookies = response.cookies();
        //未登录成功,尝试登陆湖工大首页
        if (cookies.get("Role") == null) {
            throw new PasswordErrorException();
        }
        return response.cookies();
    }

    /**
     * 设置请求参数
     */
    private static Map<String, String> getDataMapForSso(String username, String password, String lt) {
        Map<String, String> dateMap = new HashMap<>(16);
        dateMap.put("_eventId", "submit");
        dateMap.put("lt", lt);
        dateMap.put("loginType", "0");
        dateMap.put("username", username);
        dateMap.put("password", password);
        dateMap.put("j_digitPicture", "");
        return dateMap;
    }

    /**
     * 登陆湖工大首页
     */
    public static Map<String, String> loginSso(String username, String password) throws IOException, PasswordErrorException {
        Connection.Response response = Jsoup.connect(LOGIN_SSO_URL).ignoreContentType(true).method(Connection.Method.GET).timeout(10000).execute();
        Document document = response.parse();
        Elements input = document.select("input");
        String lt = input.attr("value");
        Map<String, String> data = getDataMapForSso(username, password, lt);
        Connection.Response response2 = Jsoup.connect(LOGIN_SSO_URL).ignoreContentType(true).method(Connection.Method.POST).data(data).cookies(response.cookies()).timeout(10000).execute();
        Document document2 = response2.parse();
        String title = document2.title();
        log.info(LogUtil.getMessage("title:"+title));
        if(TITLE.equals(title)){
            throw new PasswordErrorException();
        }
        return response2.cookies();
    }

    public static void main(String[] args) throws IOException, PasswordErrorException {
        loginSso("1910300711","02033814");
    }


    /**
     * 获取班级课表doc
     *
     * @param className 班级名
     * @return doc
     * @throws PasswordErrorException 密码错误
     */
    public static Document getClassScheduleDoc(String className) throws PasswordErrorException, IOException {
        Map<String, String> cookie = login();
        return getDocWithCookie(CLASS_SCHEDULE_URL + className, cookie);
    }


    /**
     * 设置请求参数
     */
    private static Map<String, String> getDataMapLoginForJson(String username, String password) {
        Map<String, String> dateMap = new HashMap<>(4);
        dateMap.put("Mobile", "1");
        dateMap.put("UserName", username);
        dateMap.put("Password", password);
        dateMap.put("Role", "Student");
        return dateMap;
    }

    /**
     * 获取个人课表doc
     *
     * @param username 学号
     * @param password 密码
     * @return doc
     * @throws PasswordErrorException 密码错误
     */
    public static Document getScheduleDoc(String username, String password) throws IOException, PasswordErrorException {
        Map<String, String> cookie = login(username, password);
        return getDocWithCookie(MY_SCHEDULE_URL, cookie);
    }


    /**
     * 获取地点课表doc
     *
     * @param classRoom 教室名
     */
    public static Document getPlaceScheduleDoc(String classRoom) throws PasswordErrorException, IOException {
        Map<String, String> cookie = login();
        return getDocWithCookie(RIGHT_PLACE_SCHEDULE_URL+classRoom, cookie);
    }


    /**
     * 获取个人信息doc
     */
    public static Document getStuInfoDoc(String username, String password) throws PasswordErrorException, IOException {
        Map<String, String> cookie = login(username, password);
        return getDocWithCookie(OWN_INFO_URL, cookie);
    }


    public static Document getAllClassRoomDoc() throws IOException, PasswordErrorException {
        Map<String, String> cookie = login();
        return getDocWithCookie(PLACE_SCHEDULE_URL, cookie);
    }

    /**
     * 获取全校所有班级名doc
     */
    public static Document getAllClassDoc() throws PasswordErrorException, IOException {
        Map<String, String> cookie = login();
        return getDocWithCookie(ALL_CLASS_URL, cookie);
    }

    /**
     * 获取指定学期学生成绩和考试信息的doc
     */
    public static Document getStuGradesDoc(String username, String password, String termId, String type) throws PasswordErrorException, IOException {
        Map<String, String> cookie = login(username, password);
        Document document;
        if ("ViewBukaoSchedule".equals(type)) {
            document = getDocWithCookie(STUDENT_GRADES_URL+ type, cookie);
        } else if (termId == null || "".equals(termId)) {
            document = getDocWithCookie(STUDENT_GRADES_URL + type, cookie);
        } else {
            document = getDocWithCookie(STUDENT_GRADES_URL +type + "?SemesterName=" + termId, cookie);
        }
        return document;
    }
}
